package com.zrkizzy.module.system.service.resource;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.zrkizzy.common.core.utils.IdUtil;
import com.zrkizzy.common.models.domain.system.resource.ModuleResource;
import com.zrkizzy.common.models.dto.system.resource.ModuleResourceDTO;
import com.zrkizzy.common.models.query.system.resource.ModuleResourceQuery;
import com.zrkizzy.common.models.vo.system.resource.ResourceLeafVO;
import com.zrkizzy.common.models.vo.system.resource.ResourceTreeVO;
import com.zrkizzy.common.models.vo.system.resource.ResourceVO;
import com.zrkizzy.module.security.OpenPolicyAgentAuthorizationManager;
import com.zrkizzy.module.system.exception.SystemErrorCode;
import com.zrkizzy.module.system.mapper.resource.ModuleResourceMapper;
import com.zrkizzy.system.facade.service.resource.IModuleResourceService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.map.HashedMap;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * <p>
 * 资源模块关联业务逻辑接口实现类
 * </p>
 *
 * @author zhangrongkang
 * @since 2023/7/27
 */
@Service
@Slf4j
public class ModuleResourceServiceImpl implements IModuleResourceService {

    @Autowired
    private OpenPolicyAgentAuthorizationManager authorizationManager;

    @Autowired
    private IdUtil idUtil;

    @Autowired
    private ModuleResourceMapper moduleResourceMapper;

    /**
     * 分页获取指定模块请求资源
     *
     * @param moduleResourceQuery 模块资源关联查询对象
     * @return 指定模块请求资源
     */
    @Override
    public Page<ResourceVO> listByModuleId(ModuleResourceQuery moduleResourceQuery) {
        // 开启分页
        Page<ModuleResource> page = new Page<>(moduleResourceQuery.getCurrentPage(), moduleResourceQuery.getPageSize());
        return moduleResourceMapper.pageByModuleId(page, moduleResourceQuery);
    }

    /**
     * 根据模块ID获取当前模块可以添加的资源
     *
     * @param id 模块ID
     * @return 请求资源树形数据返回对象
     */
    @Override
    public List<ResourceTreeVO> listResourceById(Long id) {
        // 获取当前模块中所有可以添加的资源集合
        List<ResourceLeafVO> leafList = moduleResourceMapper.findMissingResourceByModuleId(id);
        Map<String, List<ResourceLeafVO>> map = new HashedMap<>();
        // 按照请求路径进行分组
        for (ResourceLeafVO leaf : leafList) {
            // 获取请求链接
            String url = leaf.getUrl();
            // 截取出前面分组标签
            String key = subLabelFromUrl(url);
            // 如果存在当前键则获取对应集合，不存在则创建一个新的空集合
            List<ResourceLeafVO> resourceList = map.getOrDefault(key, new ArrayList<>());
            // 添加数据到集合和Map中
            resourceList.add(leaf);
            map.put(key, resourceList);
        }
        List<ResourceTreeVO> result = new ArrayList<>();
        // 将Map转为请求转为树形返回对象
        for (String label : map.keySet()) {
            // 构建资源树对象并添加到集合中
            result.add(ResourceTreeVO.builder()
                    .label(label).children(map.get(label)).build());
        }
        return result;
    }

    /**
     * 通过模块ID获取当前模块已有的请求资源
     *
     * @param moduleId 模块ID
     * @return 当前模块中已有的资源ID集合
     */
    @Override
    public List<Long> listCheckById(Long moduleId) {
        // 获取并返回当前已有的ID集合
        return moduleResourceMapper.listCheckById(moduleId);
    }

    /**
     * 批量删除指定模块中资源
     *
     * @param ids 模块资源关联ID集合
     * @return 是否删除成功
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean delete(List<Long> ids) {
        return moduleResourceMapper.deleteBatchIds(ids) == ids.size();
    }

    /**
     * 为指定模块分配资源请求
     *
     * @param moduleResourceDTO 模块资源关联对象
     * @return 是否保存成功
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean save(ModuleResourceDTO moduleResourceDTO) {
        // 对应模块ID
        Long moduleId = moduleResourceDTO.getModuleId();
        // 先删除对应模块的所有权限
        moduleResourceMapper.deleteByModuleId(moduleId);
        // 将当前所有的资源添加到对应模块中
        List<Long> resourceIds = moduleResourceDTO.getResourceIds();
        List<ModuleResource> list = new ArrayList<>();
        for (Long resourceId : resourceIds) {
            ModuleResource moduleResource = new ModuleResource();
            // ID
            moduleResource.setId(idUtil.nextId());
            // 模块ID
            moduleResource.setModuleId(moduleId);
            // 资源ID
            moduleResource.setResourceId(resourceId);
            // 创建时间
            moduleResource.setCreateTime(LocalDateTime.now());
            list.add(moduleResource);
        }
        // 判断是否添加成功
        if (moduleResourceMapper.insertBatch(list) == resourceIds.size()) {
            // 如果添加成功则清空当前项目中存储的权限
            authorizationManager.clearResourceData();
            // 返回正确
            return Boolean.TRUE;
        }
        throw SystemErrorCode.ASSOCIATION_RESOURCE_ERROR.exception();
    }

    /**
     * 从请求URL中截取出分组标签
     *
     * @param url 请求URL
     * @return 分组标签名称
     */
    private String subLabelFromUrl(String url) {
        // 定义要找到的字符
        char target = '/';
        // 出现次数
        int count = 0;
        StringBuilder result = new StringBuilder();
        // 循环遍历当前请求路径
        for (int i = 0; i < url.length(); i++) {
            // 如果当前位置是'/'，计数器加1
            if (url.charAt(i) == target) {
                count++;
            }
            // 如果出现第三次，直接将拼接的内容返回
            if (count == 3) {
                return result.toString();
            } else {
                result.append(url.charAt(i));
            }
        }
        // 抛出异常
        throw SystemErrorCode.URL_EXTRACT_LABEL_ERROR.exception(url);
    }

}
